package org.newlucene.core.index;

import java.io.IOException;
import org.newlucene.core.store.InputStream;
import org.newlucene.core.util.BitVector;

final class SegmentTermPostings implements TermPostings
{
    protected SegmentReader segReader;
    protected InputStream freqStream;
    protected BitVector deletedDocs;
    protected int doc = 0;

    protected int docCount;
	private int proxCount;
	
    protected int freq;
	private int position;
	
	boolean isPos = true;
  
	SegmentTermPostings(SegmentReader segReader) throws IOException
	{
        this.segReader = segReader;
        this.freqStream = (InputStream) segReader.freqStream.clone();
        this.deletedDocs = segReader.deletedDocs;
	}

    public void seek(Term term) throws IOException
    {
    	// since we have just one IndexReader and it is shared by multiple threads for searching
    	// each IndexReader has just one copy of the tis, so we need to protect the tis and 
    	// make the seek and read atomic, so that it is thread-safe
    	synchronized(segReader.tis)
    	{
    		TermInfo ti = segReader.tis.seek(term);
    		seek(ti);
    	}
        this.isPos = segReader.fieldInfos.getFieldInfo(term.field).isPos();
    }

	private void seek(TermInfo ti) throws IOException 
	{
        if (ti == null)
        {
            docCount = 0;
            proxCount = 0;
        }
        else
        {
            docCount = ti.docCount;
            doc = 0;
            proxCount = 0;
            position = 0;
            freqStream.seek(ti.freqPointer);
        }
	}

	public final void close() throws IOException
	{
		freqStream.close();
	}
	
    public int doc()
    {
        return doc;
    }
    
    public int freq()
    {
        return freq;
    }

	public final int nextPosition() throws IOException 
	{
		proxCount--;
		return position += freqStream.readVInt();
	}

	public final int position()
	{
		return position;
	}
  
	// skip unread positions
	protected final void skipPositions() throws IOException 
	{
		for (int f = proxCount; f > 0; f--)
		{
			freqStream.readVInt();
		}
	}

	public final boolean nextDoc() throws IOException 
	{
		if (isPos)
		{
			skipPositions();
		}
		
        while (true)
        {
            if (docCount == 0)
            {
            	return false;
            }

            int docCode = freqStream.readVInt();
            doc += docCode >>> 1; // shift off low bit
            if ((docCode & 1) != 0) // if low bit is set
            {
                freq = 1; // freq is one
            }
            else
            {
                freq = freqStream.readVInt(); // else read freq
            }
            
            docCount--;

			proxCount = freq;				  // note frequency
			position = 0;				  // reset position            
            
            if (deletedDocs == null || !deletedDocs.get(doc))
            {
    			return true;
            }

            if (isPos)
            {
            	skipPositions();	// skip deleted document
            }
        }
	}
	
	/** As yet unoptimized implementation. */
	public boolean skipTo(int target) throws IOException
	{
		do
		{
			if (!nextDoc()) return false;
		}
		while (target > doc);
		return true;
  	}
}